/***
 * * PROJECT
 * *    Logical Neighborhood Routing
 * * VERSION
 * *    $Revision: 1.9 $
 * * DATE
 * *    $Date: 2007/02/02 11:23:59 $
 * * LOG
 * *    $Log: StartSwansSim.java,v $
 * *    Revision 1.9  2007/02/02 11:23:59  lmottola
 * *    Benchmarking code for compiler in.
 * *
 * *    Revision 1.8  2007/01/04 09:14:09  lmottola
 * *    Changed constructor for AtagManager.
 * *
 * *    Revision 1.7  2006/12/20 23:05:23  lmottola
 * *    Code refactoring.
 * *
 * *    Revision 1.6  2006/12/20 22:09:46  lmottola
 * *    Changed method names.
 * *
 * *    Revision 1.5  2006/12/14 05:15:17  lmottola
 * *    Moved Estimator in atag.compiler and various cleanup.
 * *
 * *    Revision 1.4  2006/11/05 21:11:30  lmottola
 * *    Added pre-built AtagManager for traffic app.
 * *
 * *    Revision 1.3  2006/11/04 02:40:00  lmottola
 * *    Implemented topology creation for SWANS.
 * *
 * *    Revision 1.2  2006/11/03 23:09:36  lmottola
 * *    Changed nodeAttributes package.
 * *
 * *    Revision 1.1  2006/11/03 23:08:14  lmottola
 * *    Traffic application beta running.
 * *
 * *
 * *   Logical Neighborhoods Routing - Java Version
 * *                                
 * *
 * *   This program is free software; you can redistribute it and/or
 * *   modify it under the terms of the GNU General Public License
 * *   as published by the Free Software Foundation; either version 2
 * *   of the License, or (at your option) any later version.
 * *
 * *   This program is distributed in the hope that it will be useful,
 * *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 * *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * *   GNU General Public License for more details.
 * *
 * *   You should have received a copy of the GNU General Public License
 * *   along with this program; if not, you may find a copy at the FSF web
 * *   site at 'www.gnu.org' or 'www.fsf.org', or you may write to the
 * *   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * *   Boston, MA  02111-1307, USA
 ***/

package atag.apps.traffic;

import java.util.ArrayList;
import java.util.Random;
import java.util.Vector;

import jist.runtime.JistAPI;
import jist.swans.Constants;
import jist.swans.app.AppJava;
import jist.swans.field.Field;
import jist.swans.field.Mobility;
import jist.swans.mac.MacAddress;
import jist.swans.mac.MacDumb;
import jist.swans.misc.Location;
import jist.swans.misc.Mapper;
import jist.swans.misc.Util;
import jist.swans.net.NetAddress;
import jist.swans.net.NetIp;
import jist.swans.net.PacketLoss;
import jist.swans.radio.RadioInfo;
import jist.swans.radio.RadioNoise;
import jist.swans.radio.RadioNoiseIndep;
import jist.swans.radio.RadioInfo.RadioInfoShared;
import jist.swans.trans.TransUdp;
import atag.common.ATaGDataItemDeclaration;
import atag.common.ATaGProgram;
import atag.common.ATaGTaskDeclaration;
import atag.common.ScopedChannel;
import atag.runtime.AtagManager;
import atag.runtime.DataPool;
import atag.runtime.NodeInfo;
import atag.runtime.NodeLocation;
import atag.runtime.ln.DatagramObjectIO;
import atag.runtime.ln.LogicalNeighborhood;
import atag.runtime.ln.nodeAttributes.IntegerAttribute;
import atag.runtime.ln.nodeAttributes.SetAttribute;
import atag.runtime.ln.swans.SimulationReferences;
import atag.runtime.platformDependent.JiSTClock;

public class StartSwansSim {

	private static int nextNodeId = 0;

	private static final int RANDOM_SEED = 12345;

	public static void createNode(Field field,
			RadioInfo.RadioInfoShared radioInfoShared, Mapper protMap,
			PacketLoss plIn, PacketLoss plOut, NodeInfo info,
			ATaGProgram atagPrg) throws NoSuchMethodException {

		int id = info.getMyId();

		// Create entities
		RadioNoise radio = new RadioNoiseIndep(id, radioInfoShared);
		MacDumb mac = new MacDumb(new MacAddress(id), radio.getRadioInfo());
		NetAddress netAddr = NetAddress.LOCAL;
		NetIp net = new NetIp(netAddr, protMap, plIn, plOut);
		TransUdp udp = new TransUdp();

		// hookup entities
		Location location = new Location.Location2D(
				info.getMyLocation().getX(), info.getMyLocation().getY());
		field.addRadio(radio.getRadioInfo(), radio.getProxy(), location);
		field.startMobility(radio.getRadioInfo().getUnique().getID());

		// radio hookup
		radio.setFieldEntity(field.getProxy());
		radio.setMacEntity(mac.getProxy());

		// mac hookup
		mac.setRadioEntity(radio.getProxy());
		byte intId = net.addInterface(mac.getProxy());
		mac.setNetEntity(net.getProxy(), intId);

		// net hookup
		net.setProtocolHandler(Constants.NET_PROTOCOL_UDP, udp.getProxy());

		// trans hookup
		udp.setNetEntity(net.getProxy());

		SimulationReferences.setNodeInfo(id, info);

		DatagramObjectIO objectIO = new DatagramObjectIO(
				LogicalNeighborhood.PORT, LogicalNeighborhood.BUFFER_SIZE,
				LogicalNeighborhood.RECEIVE_TIMEOUT);
		SimulationReferences.setObjectIO(id, objectIO);
		AppJava runObjectIO = new AppJava(DatagramObjectIO.class);
		runObjectIO.setUdpEntity(udp.getProxy());
		runObjectIO.getProxy().run(new String[] { String.valueOf(id) });
		JistAPI.sleep(1);

		LogicalNeighborhood ln = new LogicalNeighborhood(info, objectIO);
		SimulationReferences.setLN(id, ln);
		AppJava runLNTick = new AppJava(LogicalNeighborhood.class);
		runLNTick.setUdpEntity(udp.getProxy());
		runLNTick.getProxy().run(
				new String[] { "tickStart", String.valueOf(id) });
		JistAPI.sleep(1);
		AppJava runLNQueue = new AppJava(LogicalNeighborhood.class);
		runLNQueue.setUdpEntity(udp.getProxy());
		runLNQueue.getProxy().run(
				new String[] { "queueStart", String.valueOf(id) });
		JistAPI.sleep(1);

		AtagManager atagManager = new PreBuiltAtagManager();
		atagManager.setAtagProgram(atagPrg);
		atagManager.setNodeInfo(info);
		atagManager.setDataPool(new DataPool(ln, info, atagManager));
		atagManager.setUp();
		SimulationReferences.setAtagManager(id, atagManager);

		AppJava runAtagManager = new AppJava(AtagManager.class);
		runAtagManager.setUdpEntity(udp.getProxy());
		for (int i = 0; i < atagPrg.numTasks(); i++) {
			JistAPI.sleep(1);
			runAtagManager.getProxy().run(
					new String[] { String.valueOf(id), String.valueOf(i) });
		}
	}

	public static void main(String[] args) {
		try {

			Location.Location2D bounds = new Location.Location2D(100000, 100000);
			Mobility mobility = new Mobility.Static();

			Field field = new Field(bounds);
			field.setMobility(mobility);
			RadioInfo.RadioInfoShared radioInfoShared = RadioInfo.createShared(
					Constants.FREQUENCY_DEFAULT, Constants.BANDWIDTH_DEFAULT,
					Constants.TRANSMIT_DEFAULT, Constants.GAIN_DEFAULT, Util
							.fromDB(Constants.SENSITIVITY_DEFAULT), Util
							.fromDB(Constants.THRESHOLD_DEFAULT),
					Constants.TEMPERATURE_DEFAULT,
					Constants.TEMPERATURE_FACTOR_DEFAULT,
					Constants.AMBIENT_NOISE_DEFAULT);
			// protocol mapper
			Mapper protMap = new Mapper(Constants.NET_PROTOCOL_MAX);
			protMap.mapToNext(Constants.NET_PROTOCOL_UDP);

			// packet loss
			PacketLoss pl = new PacketLoss.Zero();

			ATaGProgram atagPrg = returnTrafficApplication();
			atagPrg.sanitize();

			int routingNodeSpacing = (int) Math.sqrt(0.6
					* TrafficTopologyGenerator.COMM_RANGE
					* TrafficTopologyGenerator.COMM_RANGE + TrafficTopologyGenerator.N_LANES
					* TrafficTopologyGenerator.LANE_SPACE);
			buildRoadSideNetwork(field, radioInfoShared, protMap, pl, atagPrg,
					routingNodeSpacing, 100000);

			for (int i = 0; i < TrafficTopologyGenerator.HS_NUMBER; i++) {
				buildHS(field, radioInfoShared, protMap, pl, atagPrg, i,
						TrafficTopologyGenerator.HS_SPACING,
						TrafficTopologyGenerator.N_LANES,
						TrafficTopologyGenerator.LANE_SPACE,
						TrafficTopologyGenerator.NODES_RAMP, i
								* TrafficTopologyGenerator.HS_SPACING);
			}

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private static void buildRoadSideNetwork(Field field,
			RadioInfoShared radioInfoShared, Mapper protMap, PacketLoss pl,
			ATaGProgram atagPrg, int spacing, int upperBound) {

		try {
			for (int i = 0; i < upperBound; i += spacing) {
				// A simple routing node
				System.out.println("Placing routing node id " + nextNodeId
						+ " at " + 0 + "," + i);
				NodeInfo typeRouting = new NodeInfo(nextNodeId++,
						new NodeLocation(0, i), new Vector(), 1, new Vector(),
						new JiSTClock());
				createNode(field, radioInfoShared, protMap, pl, pl,
						typeRouting, atagPrg);
				Thread.sleep(1000);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private static void buildHS(Field field, RadioInfoShared radioInfoShared,
			Mapper protMap, PacketLoss pl, ATaGProgram atagPrg, int HSid,
			int HSspacing, int nLanes, int laneSpacing, int nodesOnRamp,
			int startingY) {

		Vector attributes, assignedTasks;
		Random rnd = new Random(RANDOM_SEED);

		// This is the number of nodes generated in this HS, we will randomly
		// choose one of these nodes to host the tasks with no specific
		// instantiation rules
		int generatedNodes = nLanes + nodesOnRamp + 2;

		// Node id for AvgSpeedCalculator
		int avgSpeedCalculatorNode = nextNodeId + rnd.nextInt(generatedNodes);
		// Node id for AvgQueueCalculator
		int avgQueueCalculatorNode = nextNodeId + rnd.nextInt(generatedNodes);
		// Node id for RGSignalCalculator
		int rGSignalCalculatorNode = nextNodeId + rnd.nextInt(generatedNodes);
		// Node id for SpeedLimitCalculator
		int speedLimitCalculatorNode = nextNodeId + rnd.nextInt(generatedNodes);

		try {
			// Creating SpeedSampler tasks
			for (int i = 0; i < nLanes; i++) {

				// Generating random position within this HS and lane
				int x = i * laneSpacing + laneSpacing / 2;
				int y = startingY + rnd.nextInt(HSspacing);
				System.out.println("Placing SpeedSampler on node id "
						+ nextNodeId + " in HS " + HSid + " at " + x + "," + y);

				// Creating the node
				attributes = new Vector();
				attributes.add(new IntegerAttribute("HS", HSid));
				assignedTasks = new Vector();
				assignedTasks.add(new Integer(IDConstants.T_SPEEDSAMPLER));
				assignAdditionalTask(nextNodeId, assignedTasks,
						avgSpeedCalculatorNode, avgQueueCalculatorNode,
						rGSignalCalculatorNode, speedLimitCalculatorNode);
				NodeInfo typeSpeedSampler = new NodeInfo(nextNodeId++,
						new NodeLocation(x, y), attributes, 1, assignedTasks,
						new JiSTClock());
				createNode(field, radioInfoShared, protMap, pl, pl,
						typeSpeedSampler, atagPrg);
				Thread.sleep(1000);
			}

			// Creating RampSampler tasks
			for (int i = 0; i < nodesOnRamp; i++) {

				// Generating position
				int x = (nLanes + i) * laneSpacing;
				int y = startingY + (HSspacing / 2)
						- (i * TrafficTopologyGenerator.COMM_RANGE / 2); // Arbitrary
				System.out.println("Placing RampSampler task on node id "
						+ nextNodeId + " in HS " + HSid + " at " + x + "," + y);

				// Creating the node
				attributes = new Vector();
				attributes.add(new IntegerAttribute("HS", HSid));
				assignedTasks = new Vector();
				assignedTasks.add(new Integer(IDConstants.T_RAMPSAMPLER));
				assignAdditionalTask(nextNodeId, assignedTasks,
						avgSpeedCalculatorNode, avgQueueCalculatorNode,
						rGSignalCalculatorNode, speedLimitCalculatorNode);
				NodeInfo typeRampSampler = new NodeInfo(nextNodeId++,
						new NodeLocation(x, y), attributes, 1, assignedTasks,
						new JiSTClock());
				createNode(field, radioInfoShared, protMap, pl, pl,
						typeRampSampler, atagPrg);
				Thread.sleep(1000);
			}

			// Creating the SpeedLimitDisplayer
			attributes = new Vector();
			attributes.add(new IntegerAttribute("HS", HSid));
			attributes.add(new SetAttribute("attachedActuators",
					new String[] { "SpeedLimitDisplayer" }));
			assignedTasks = new Vector();
			assignedTasks.add(new Integer(IDConstants.T_SLDISPLAYER));
			System.out.println("Placing SpeedLimitDisplayer task on node id "
					+ nextNodeId + " in HS " + HSid + " at " + 0 + ","
					+ (startingY + HSspacing));
			assignAdditionalTask(nextNodeId, assignedTasks,
					avgSpeedCalculatorNode, avgQueueCalculatorNode,
					rGSignalCalculatorNode, speedLimitCalculatorNode);

			NodeInfo typeLimitDisplayer = new NodeInfo(nextNodeId++,
					new NodeLocation(0, startingY + HSspacing), attributes, 1,
					assignedTasks, new JiSTClock());
			createNode(field, radioInfoShared, protMap, pl, pl,
					typeLimitDisplayer, atagPrg);
			Thread.sleep(1000);

			// Creating the RGSignalDisplayer
			attributes = new Vector();
			attributes.add(new IntegerAttribute("HS", HSid));
			attributes.add(new SetAttribute("attachedActuators",
					new String[] { "RGSignalDisplayer" }));
			assignedTasks = new Vector();
			assignedTasks.add(new Integer(IDConstants.T_RGSDISPLAYER));
			System.out.println("Placing RGSignalDisplayer task on node id "
					+ nextNodeId + " in HS " + HSid + " at "
					+ (nLanes * laneSpacing) + "," + (startingY + HSspacing));
			assignAdditionalTask(nextNodeId, assignedTasks,
					avgSpeedCalculatorNode, avgQueueCalculatorNode,
					rGSignalCalculatorNode, speedLimitCalculatorNode);

			NodeInfo typeRGDisplayer = new NodeInfo(nextNodeId++,
					new NodeLocation(nLanes * laneSpacing, startingY
							+ HSspacing), attributes, 1, assignedTasks,
					new JiSTClock());
			createNode(field, radioInfoShared, protMap, pl, pl,
					typeRGDisplayer, atagPrg);
			Thread.sleep(1000);

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private static void assignAdditionalTask(int nodeId, Vector assignedTasks,
			int avgSpeedCalculatorNode, int avgQueueCalculatorNode,
			int rGSignalCalculatorNode, int speedLimitCalculatorNode) {

		if (nodeId == avgSpeedCalculatorNode) {
			System.out.println("Also assigned avgSpeedCalculator task");
			assignedTasks.add(new Integer(IDConstants.T_ASCALCULATOR));
		}
		if (nodeId == avgQueueCalculatorNode) {
			System.out.println("Also assigned avgQueueCalculator task");
			assignedTasks.add(new Integer(IDConstants.T_AQLENCALCULATOR));
		}
		if (nodeId == rGSignalCalculatorNode) {
			System.out.println("Also assigned rGSignalCalculator task");
			assignedTasks.add(new Integer(IDConstants.T_RGSCALCULATOR));
		}
		if (nodeId == speedLimitCalculatorNode) {
			System.out.println("Also assigned speedLimitCalculatorTask");
			assignedTasks.add(new Integer(IDConstants.T_SLCALCULATOR));
		}
	}

	public static ATaGProgram returnTrafficApplication() {

		ATaGTaskDeclaration newTask;
		int[] tempFiringRule;
		int[] tempTaskLocation;

		ATaGProgram retProgram = new ATaGProgram();

		// set the tasks
		ArrayList<ATaGTaskDeclaration> tList = retProgram.getTaskList();

		// RampSampler
		newTask = new ATaGTaskDeclaration();
		newTask.setName("RampSampler");

		tempFiringRule = new int[2];
		tempFiringRule[0] = ATaGTaskDeclaration.FIRING_PERIODIC;
		tempFiringRule[1] = 10;
		newTask.setFiringRule(tempFiringRule);
		newTask.setRunAtInit(true);

		tempTaskLocation = new int[2];
		tempTaskLocation[0] = ATaGTaskDeclaration.INSTANTIATION_NODES_PER_INSTANCE;
		// set number of nodes per instance as the other element
		tempTaskLocation[1] = 1;
		newTask.setLocation(tempTaskLocation);
		newTask.setAt(true);
		newTask.setSlash(false);
		newTask.setNeededAttribute(new SetAttribute("attachedSensors",
				new String[] { "PresenceSensor" }));

		tList.add(newTask);

		// SpeedSampler
		newTask = new ATaGTaskDeclaration();
		newTask.setName("SpeedSampler");

		tempFiringRule = new int[2];
		tempFiringRule[0] = ATaGTaskDeclaration.FIRING_PERIODIC;
		tempFiringRule[1] = 10;
		newTask.setFiringRule(tempFiringRule);
		newTask.setRunAtInit(true);

		tempTaskLocation = new int[2];
		tempTaskLocation[0] = ATaGTaskDeclaration.INSTANTIATION_NODES_PER_INSTANCE;
		// set number of nodes per instance as the other element
		tempTaskLocation[1] = 1;
		newTask.setLocation(tempTaskLocation);
		newTask.setAt(true);
		newTask.setSlash(false);
		newTask.setNeededAttribute(new SetAttribute("attachedSensors",
				new String[] { "SpeedSensor" }));

		tList.add(newTask);

		// AverageQueueLengthCalculator
		newTask = new ATaGTaskDeclaration();
		newTask.setName("AverageQueueLengthCalculator");

		tempFiringRule = new int[2];
		tempFiringRule[0] = ATaGTaskDeclaration.FIRING_ANYDATA;
		tempFiringRule[1] = 0;
		newTask.setFiringRule(tempFiringRule);
		newTask.setRunAtInit(false);

		tempTaskLocation = new int[2];
		tempTaskLocation[0] = ATaGTaskDeclaration.INSTANTIATION_NODES_PER_INSTANCE;
		// set number of nodes per instance as the other element
		tempTaskLocation[1] = 1;
		newTask.setLocation(tempTaskLocation);
		newTask.setAt(false);
		newTask.setSlash(true);

		// Luca - how do I say "HighWayScope ..
		// I just want a string to be a predicate"
		newTask.setMyRegionName(new String("HS"));

		tList.add(newTask);

		// AverageSpeedCalculator
		newTask = new ATaGTaskDeclaration();
		newTask.setName("AverageSpeedCalculator");

		tempFiringRule = new int[2];
		tempFiringRule[0] = ATaGTaskDeclaration.FIRING_ANYDATA;
		tempFiringRule[1] = 0;
		newTask.setFiringRule(tempFiringRule);
		newTask.setRunAtInit(false);

		tempTaskLocation = new int[2];
		tempTaskLocation[0] = ATaGTaskDeclaration.INSTANTIATION_NODES_PER_INSTANCE;
		// set number of nodes per instance as the other element
		tempTaskLocation[1] = 1;
		newTask.setLocation(tempTaskLocation);
		newTask.setAt(false);
		newTask.setSlash(true);

		// Luca - how do I say "HighWayScope ..
		// I just want a string to be a predicate"
		newTask.setMyRegionName(new String("HS"));

		tList.add(newTask);

		// SpeedLimitCalculator
		newTask = new ATaGTaskDeclaration();
		newTask.setName("SpeedLimitCalculator");

		tempFiringRule = new int[2];
		tempFiringRule[0] = ATaGTaskDeclaration.FIRING_ANYDATA;
		tempFiringRule[1] = 0;
		newTask.setFiringRule(tempFiringRule);
		newTask.setRunAtInit(false);

		tempTaskLocation = new int[2];
		tempTaskLocation[0] = ATaGTaskDeclaration.INSTANTIATION_NODES_PER_INSTANCE;
		// set number of nodes per instance as the other element
		tempTaskLocation[1] = 1;
		newTask.setLocation(tempTaskLocation);
		newTask.setAt(false);
		newTask.setSlash(true);

		// Luca - how do I say "HighWayScope ..
		// I just want a string to be a predicate"
		newTask.setMyRegionName(new String("HS"));

		tList.add(newTask);

		// RGSignalCalculator
		newTask = new ATaGTaskDeclaration();
		newTask.setName("RGSignalCalculator");

		tempFiringRule = new int[2];
		tempFiringRule[0] = ATaGTaskDeclaration.FIRING_ANYDATA;
		tempFiringRule[1] = 0;
		newTask.setFiringRule(tempFiringRule);
		newTask.setRunAtInit(false);

		tempTaskLocation = new int[2];
		tempTaskLocation[0] = ATaGTaskDeclaration.INSTANTIATION_NODES_PER_INSTANCE;
		// set number of nodes per instance as the other element
		tempTaskLocation[1] = 1;
		newTask.setLocation(tempTaskLocation);
		newTask.setAt(false);
		newTask.setSlash(true);

		// Luca - how do I say "HighWayScope ..
		// I just want a string to be a predicate"
		newTask.setMyRegionName(new String("HS"));

		tList.add(newTask);

		// SpeedLimitDisplayer
		newTask = new ATaGTaskDeclaration();
		newTask.setName("SpeedLimitDisplayer");

		tempFiringRule = new int[2];
		tempFiringRule[0] = ATaGTaskDeclaration.FIRING_ANYDATA;
		tempFiringRule[1] = 0;
		newTask.setFiringRule(tempFiringRule);
		newTask.setRunAtInit(false);

		tempTaskLocation = new int[2];
		tempTaskLocation[0] = ATaGTaskDeclaration.INSTANTIATION_NODES_PER_INSTANCE;
		// set number of nodes per instance as the other element
		tempTaskLocation[1] = 1;
		newTask.setLocation(tempTaskLocation);
		newTask.setAt(true);
		newTask.setSlash(false);
		newTask.setNeededAttribute(new SetAttribute("attachedActuators",
				new String[] { "SpeedLimitDisplayer" }));

		tList.add(newTask);

		// RGSignalDisplayer
		newTask = new ATaGTaskDeclaration();
		newTask.setName("RGSignalDisplayer");

		tempFiringRule = new int[2];
		tempFiringRule[0] = ATaGTaskDeclaration.FIRING_ANYDATA;
		tempFiringRule[1] = 0;
		newTask.setFiringRule(tempFiringRule);
		newTask.setRunAtInit(false);

		tempTaskLocation = new int[2];
		tempTaskLocation[0] = ATaGTaskDeclaration.INSTANTIATION_NODES_PER_INSTANCE;
		// set number of nodes per instance as the other element
		tempTaskLocation[1] = 1;
		newTask.setLocation(tempTaskLocation);
		newTask.setAt(true);
		newTask.setSlash(false);

		newTask.setNeededAttribute(new SetAttribute("attachedActuators",
				new String[] { "RGSignalDisplayer" }));

		tList.add(newTask);

		// now populate the data list
		ArrayList<ATaGDataItemDeclaration> dList = retProgram.getDataList();
		ATaGDataItemDeclaration newDataItem;
		newDataItem = new ATaGDataItemDeclaration();
		newDataItem.setName(new String("VehiclePresence"));
		dList.add(newDataItem);

		newDataItem = new ATaGDataItemDeclaration();
		newDataItem.setName(new String("RawSpeed"));
		dList.add(newDataItem);

		newDataItem = new ATaGDataItemDeclaration();
		newDataItem.setName(new String("AverageQueueLength"));
		dList.add(newDataItem);

		newDataItem = new ATaGDataItemDeclaration();
		newDataItem.setName(new String("AverageSpeed"));
		dList.add(newDataItem);

		newDataItem = new ATaGDataItemDeclaration();
		newDataItem.setName(new String("SpeedLimit"));
		dList.add(newDataItem);

		newDataItem = new ATaGDataItemDeclaration();
		newDataItem.setName(new String("RGSignal"));
		dList.add(newDataItem);

		// now populate the channel list
		ArrayList<ScopedChannel> cList = retProgram.getChannelList();
		ScopedChannel newChannel;

		newChannel = new ScopedChannel();
		newChannel.setDataName(new String("VehiclePresence"));
		newChannel.setDirection(ScopedChannel.CHANNEL_TYPE_OUTPUT);
		newChannel.setInterest(new String("none:0"));
		newChannel.setLocalFlag(true);
		newChannel.setTaskName(new String("RampSampler"));
		cList.add(newChannel);

		newChannel = new ScopedChannel();
		newChannel.setDataName(new String("RawSpeed"));
		newChannel.setDirection(ScopedChannel.CHANNEL_TYPE_OUTPUT);
		newChannel.setInterest(new String("none:0"));
		newChannel.setLocalFlag(true);
		newChannel.setTaskName(new String("SpeedSampler"));
		cList.add(newChannel);

		newChannel = new ScopedChannel();
		newChannel.setDataName(new String("VehiclePresence"));
		newChannel.setDirection(ScopedChannel.CHANNEL_TYPE_INPUT);
		newChannel.setInterest(new String("domain:0"));
		newChannel.setLocalFlag(true);
		newChannel.setTaskName(new String("AverageQueueLengthCalculator"));
		cList.add(newChannel);

		newChannel = new ScopedChannel();
		newChannel.setDataName(new String("RawSpeed"));
		newChannel.setDirection(ScopedChannel.CHANNEL_TYPE_INPUT);
		newChannel.setInterest(new String("domain:0"));
		newChannel.setLocalFlag(true);
		newChannel.setTaskName(new String("AverageSpeedCalculator"));
		cList.add(newChannel);

		newChannel = new ScopedChannel();
		newChannel.setDataName(new String("AverageQueueLength"));
		newChannel.setDirection(ScopedChannel.CHANNEL_TYPE_OUTPUT);
		newChannel.setInterest(new String("none:0"));
		newChannel.setLocalFlag(true);
		newChannel.setTaskName(new String("AverageQueueLengthCalculator"));
		cList.add(newChannel);

		newChannel = new ScopedChannel();
		newChannel.setDataName(new String("AverageSpeed"));
		newChannel.setDirection(ScopedChannel.CHANNEL_TYPE_OUTPUT);
		newChannel.setInterest(new String("none:0"));
		newChannel.setLocalFlag(true);
		newChannel.setTaskName(new String("AverageSpeedCalculator"));
		cList.add(newChannel);

		newChannel = new ScopedChannel();
		newChannel.setDataName(new String("AverageQueueLength"));
		newChannel.setDirection(ScopedChannel.CHANNEL_TYPE_INPUT);
		newChannel.setInterest(new String("region-hops:1"));
		newChannel.setLocalFlag(true);
		newChannel.setTaskName(new String("SpeedLimitCalculator"));
		cList.add(newChannel);

		newChannel = new ScopedChannel();
		newChannel.setDataName(new String("AverageSpeed"));
		newChannel.setDirection(ScopedChannel.CHANNEL_TYPE_INPUT);
		newChannel.setInterest(new String("region-hops:1"));
		newChannel.setLocalFlag(true);
		newChannel.setTaskName(new String("SpeedLimitCalculator"));
		cList.add(newChannel);

		newChannel = new ScopedChannel();
		newChannel.setDataName(new String("AverageQueueLength"));
		newChannel.setDirection(ScopedChannel.CHANNEL_TYPE_INPUT);
		newChannel.setInterest(new String("region-hops:1"));
		newChannel.setLocalFlag(true);
		newChannel.setTaskName(new String("RGSignalCalculator"));
		cList.add(newChannel);

		newChannel = new ScopedChannel();
		newChannel.setDataName(new String("AverageSpeed"));
		newChannel.setDirection(ScopedChannel.CHANNEL_TYPE_INPUT);
		newChannel.setInterest(new String("region-hops:1"));
		newChannel.setLocalFlag(true);
		newChannel.setTaskName(new String("RGSignalCalculator"));
		cList.add(newChannel);

		newChannel = new ScopedChannel();
		newChannel.setDataName(new String("SpeedLimit"));
		newChannel.setDirection(ScopedChannel.CHANNEL_TYPE_OUTPUT);
		newChannel.setInterest(new String("domain:0"));
		newChannel.setLocalFlag(true);
		newChannel.setTaskName(new String("SpeedLimitCalculator"));
		cList.add(newChannel);

		newChannel = new ScopedChannel();
		newChannel.setDataName(new String("SpeedLimit"));
		newChannel.setDirection(ScopedChannel.CHANNEL_TYPE_INPUT);
		newChannel.setInterest(new String("none:0"));
		newChannel.setLocalFlag(true);
		newChannel.setTaskName(new String("SpeedLimitDisplayer"));
		cList.add(newChannel);

		newChannel = new ScopedChannel();
		newChannel.setDataName(new String("RGSignal"));
		newChannel.setDirection(ScopedChannel.CHANNEL_TYPE_OUTPUT);
		newChannel.setInterest(new String("domain:0"));
		newChannel.setLocalFlag(true);
		newChannel.setTaskName(new String("RGSignalCalculator"));
		cList.add(newChannel);

		newChannel = new ScopedChannel();
		newChannel.setDataName(new String("RGSignal"));
		newChannel.setDirection(ScopedChannel.CHANNEL_TYPE_INPUT);
		newChannel.setInterest(new String("none:0"));
		newChannel.setLocalFlag(true);
		newChannel.setTaskName(new String("RGSignalDisplayer"));
		cList.add(newChannel);

		return retProgram;
	}

}
